/*
	Programação Concorrente
	Trabalho Final
	Turma A

	Adilson Abreu Couto Rapozo Junior ( n. USP: 6402336 )
	Luiz Alfredo Bertoni ( n. USP: 6418834 )
	Rodrigo Fernandes da Costa ( n. USP: 6793073 )
*/

#include "main.h"

int process1 ( int N , int M ) {

	MPI_Status status ;
	MPI_Request request ;

	char * words ;
	char * wordsFraction ;
	char * wordsSize5 ;
	char * word ;
	int wordNumberSize5 ;
	int wordNumber ;
	int wordNumberFraction ;
	int wordMaxSize ;
	
	char * charList ;
	int charListSize ;
	
	int * matches ;
	int * matchesSize5 ;
	int matchNumber ;
	int matchNumber2 ;
	int matchNumberSize5 ;
	
	double startTime ;
	double endTime ;
	
	int i , j ;
	int stopN = 0 ;
	int stopM = 0 ;
	int newList = 0 ;
	int * newMatches ;
	int * stopMs ;

	if ( ! listWords ( & words , & wordNumber , & wordsSize5 , & wordNumberSize5 , & wordMaxSize , & charList , & charListSize ) ) return 1 ;

	stopMs = calloc ( M , sizeof ( int ) ) ;
	newMatches = calloc ( M , sizeof ( int ) ) ;
	word = calloc ( 6 , sizeof ( char ) ) ;
	matches = calloc ( wordNumber , sizeof ( int ) ) ;
	matchesSize5 = calloc ( wordNumberSize5 , sizeof ( int ) ) ;


	for ( j = 0 , i = N + 1 ; i < N + M + 1 ; ++ i ) {

		wordNumberFraction = wordNumber / M ;

		wordsFraction = words + wordNumberFraction * wordMaxSize * j ++ ;

		if ( i == N + M ) {

			wordNumberFraction +=  wordNumber % M ;
		}

		MPI_Send ( & wordNumberFraction , sizeof ( int ) , MPI_BYTE , i , 0 , MPI_COMM_WORLD ) ;
		MPI_Send ( & wordMaxSize , sizeof ( int ) , MPI_BYTE , i , 0 , MPI_COMM_WORLD ) ;
		MPI_Send ( wordsFraction , wordNumberFraction * wordMaxSize , MPI_BYTE , i , 0 , MPI_COMM_WORLD ) ;

		MPI_Send ( & wordNumberSize5 , sizeof ( int ) , MPI_BYTE , i , 0 , MPI_COMM_WORLD ) ;
		MPI_Send ( wordsSize5 , wordNumberSize5 * 6 , MPI_BYTE , i , 0 , MPI_COMM_WORLD ) ;
	}

	for ( j = 0 , i = N + 1 ; i < N + M + 1 ; ++ i , ++ j ) {

		MPI_Irecv ( & newMatches [ j ] , sizeof ( int ) , MPI_BYTE , MPI_ANY_SOURCE , NEW_LIST_TAG , MPI_COMM_WORLD , & request ) ;
		MPI_Irecv ( & stopMs [ j ] , sizeof ( int ) , MPI_BYTE , MPI_ANY_SOURCE , STOP_TAG , MPI_COMM_WORLD , & request ) ;
	}


	for ( i = 1 ; i <= N ; ++ i ) {

		MPI_Send ( & charListSize , sizeof ( int ) , MPI_BYTE , i , CHAR_LIST_SIZE_TAG , MPI_COMM_WORLD ) ;
		MPI_Send ( charList , sizeof ( char ) * charListSize , MPI_BYTE , i , CHAR_LIST_TAG , MPI_COMM_WORLD ) ;
	}
 
	newTable ( ) ;

	matchNumberSize5 = matchNumber = 0 ;
	startTime = getTime ( ) ;

	while ( ( matchNumber + matchNumberSize5 ) < ( wordNumber + wordNumberSize5 ) ) {

		for ( j = 0 , i = N + 1 ; i < N + M + 1 ; ++ i , ++ j ) {

			if ( stopMs [ j ] ) continue ; 

			if ( newMatches [ j ] ) {

				matchNumber += newMatches [ j ] ;

				if ( stopN ) {

					MPI_Recv ( & newMatches [ j ] , sizeof ( int ) , MPI_BYTE , MPI_ANY_SOURCE , NEW_LIST_TAG , MPI_COMM_WORLD , & status ) ;

				} else {

					MPI_Irecv ( & newMatches [ j ] , sizeof ( int ) , MPI_BYTE , MPI_ANY_SOURCE , NEW_LIST_TAG , MPI_COMM_WORLD , & request ) ;
				}
			}
		}


		if ( ! stopN ) {

			MPI_Recv ( word , sizeof ( char ) * 6 , MPI_BYTE , MPI_ANY_SOURCE , RANDOM_WORD_TAG , MPI_COMM_WORLD , & status ) ;

			if ( matchWord ( wordNumberSize5 , wordsSize5 , matchesSize5 , word ) ) {

				printf ( "%s\n" , word ) ;
				++ matchNumberSize5 ;


				if ( strlen ( word ) >= 2 ) {

					for ( j = 0 , i = N + 1 ; i < N + M + 1 ; ++ i , ++ j ) {

						if ( stopMs [ j ] ) continue ; 

						MPI_Send ( matchesSize5 , sizeof ( int ) * wordNumberSize5 , MPI_BYTE , i , MATCHES_5_TAG , MPI_COMM_WORLD ) ;
						MPI_Send ( word , sizeof ( char ) * 6 , MPI_BYTE , i , RANDOM_WORD_TAG , MPI_COMM_WORLD ) ;
					}
				}

			}
		}

		if ( matchNumberSize5 == wordNumberSize5 && ! stopN ) {

			stopN = 1 ;

			for ( i = 1 ; i <= N ; ++ i ) {

				MPI_Send ( & stopN , sizeof ( int ) , MPI_BYTE , i , STOP_TAG , MPI_COMM_WORLD ) ;
			}
		}

		if ( matchNumber >= ( wordNumber + wordNumberSize5 ) / 10 * i ) {
		
			endTime = getTime ( ) ;
		
			tableEntry ( i , endTime - startTime ) ;
		
			printf ( "%d0%% found. ( q to quit ) \n" , i ) ;

			if ( getchar ( ) == 'q' ) break ;
			getchar ( ) ;

			++ i ;
		}

		if ( i == 11 ) break ;
	}

	if ( ! stopN ) {

		stopN = 1 ;

		for ( i = 1 ; i <= N ; ++ i ) {

			MPI_Send ( & stopN , sizeof ( int ) , MPI_BYTE , i , STOP_TAG , MPI_COMM_WORLD ) ;
		}
	}

	if ( ! stopM ) {

		stopM = 1 ;

		for ( j = 0 , i = N + 1 ; i < N + M + 1 ; ++ i , ++ j ) {

			if ( stopMs [ j ] ) continue ; 

			MPI_Send ( & stopM , sizeof ( int ) , MPI_BYTE , i , STOP_TAG , MPI_COMM_WORLD ) ;
		}
	}

	free ( stopMs ) ;
	free ( newMatches ) ;
	free ( words ) ;
	free ( wordsSize5 ) ;
	free ( word ) ;
	free ( charList ) ;
	free ( matches ) ;
	free ( matchesSize5 ) ;

	return 0 ;
}

void processN ( void ) {

	MPI_Status status ;
	MPI_Request request ;

	int stop = 0 ;

	char * charList ;
	int charListSize ;

	char * word ;

	MPI_Recv ( & charListSize , sizeof ( int ) , MPI_BYTE , MPI_ANY_SOURCE , CHAR_LIST_SIZE_TAG , MPI_COMM_WORLD , & status ) ;

	charList = calloc ( charListSize , sizeof ( char ) ) ;

	MPI_Recv ( charList , sizeof ( char ) * charListSize , MPI_BYTE , MPI_ANY_SOURCE , CHAR_LIST_TAG , MPI_COMM_WORLD , & status ) ;

	word = calloc ( 6 , sizeof ( char ) ) ;

	MPI_Irecv ( & stop , sizeof ( int ) , MPI_BYTE , MPI_ANY_SOURCE , STOP_TAG , MPI_COMM_WORLD , & request ) ;

	while ( ! stop ) {

		newWord ( word , charList , charListSize ) ;
		MPI_Send ( word , sizeof ( char ) * 6 , MPI_BYTE , 0 , RANDOM_WORD_TAG , MPI_COMM_WORLD ) ;
	}
printf ( "%d\n" , __LINE__ ) ;
	free ( charList ) ;
	free ( word ) ;
}

void processM ( void ) {

	MPI_Status status ;
	MPI_Request request ;

	char * words ;
	char * wordsSize5 ;
	char * word ;
	int wordNumberSize5 ;
	int wordNumber ;
	int wordMaxSize ;
	
	char * charList ;
	int charListSize ;
	
	int * matches ;
	int * matchesSize5 ;
	int matchNumber = 0 ;
	int matchNumberSize5 ;
	
	double startTime ;
	double endTime ;
	
	int i ;
	int stop = 0 ;
	int newList = 0 ;
	int count = 0 ;

	MPI_Recv ( & wordNumber , sizeof ( int ) , MPI_BYTE , MPI_ANY_SOURCE , 0 , MPI_COMM_WORLD , & status ) ;
	MPI_Recv ( & wordMaxSize , sizeof ( int ) , MPI_BYTE , MPI_ANY_SOURCE , 0 , MPI_COMM_WORLD , & status ) ;
	words = calloc ( wordNumber * wordMaxSize , sizeof ( char ) ) ;
	MPI_Recv ( words , wordNumber * wordMaxSize , MPI_BYTE , MPI_ANY_SOURCE , 0 , MPI_COMM_WORLD , & status ) ;
	matches = calloc ( wordNumber , sizeof ( int ) ) ;

	MPI_Recv ( & wordNumberSize5 , sizeof ( int ) , MPI_BYTE , MPI_ANY_SOURCE , 0 , MPI_COMM_WORLD , & status ) ;
	wordsSize5 = calloc ( wordNumberSize5 * 6 , sizeof ( char ) ) ;
	MPI_Recv ( wordsSize5 , wordNumberSize5 * 6 , MPI_BYTE , MPI_ANY_SOURCE , 0 , MPI_COMM_WORLD , & status ) ;

	matchesSize5 = calloc ( wordNumberSize5 , sizeof ( int ) ) ;
	word = calloc ( 6 , sizeof ( char ) ) ;

	MPI_Recv ( matchesSize5 , sizeof ( int ) * wordNumberSize5 , MPI_BYTE , MPI_ANY_SOURCE , MATCHES_5_TAG , MPI_COMM_WORLD , & status ) ;
	MPI_Recv ( word , 6 , MPI_BYTE , MPI_ANY_SOURCE , RANDOM_WORD_TAG , MPI_COMM_WORLD , & status ) ;

	MPI_Irecv ( & stop , sizeof ( int ) , MPI_BYTE , MPI_ANY_SOURCE , STOP_TAG , MPI_COMM_WORLD , & request ) ;

	while ( ! stop && matchNumber < wordNumber ) {

		count = matchCompWord ( matchNumber , wordNumberSize5 , wordsSize5 ,  matchesSize5 , wordNumber , wordMaxSize , words , matches , word ) ;

		matchNumber += count ;

		if ( count ) MPI_Send ( & count , sizeof ( int ) , MPI_BYTE , 0 , MATCHES_TAG , MPI_COMM_WORLD ) ;

		MPI_Recv ( matchesSize5 , sizeof ( int ) * wordNumberSize5 , MPI_BYTE , MPI_ANY_SOURCE , MATCHES_5_TAG , MPI_COMM_WORLD , & status ) ;
		MPI_Recv ( word , 6 , MPI_BYTE , MPI_ANY_SOURCE , RANDOM_WORD_TAG , MPI_COMM_WORLD , & status ) ;
	}

	stop = 1 ;

	MPI_Send ( & stop , sizeof ( int ) , MPI_BYTE , 0 , STOP_TAG , MPI_COMM_WORLD ) ;

	free ( word ) ;
	free ( matchesSize5  ) ;
	free ( wordsSize5 ) ;
	free ( matches ) ;
	free ( words ) ;

}

